home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Tool Chest / Files / XTND 1.3.6 / Application Examples / PascalSource / XTEStyleSample.p < prev    next >
Encoding:
Text File  |  1992-01-16  |  51.0 KB  |  1,645 lines  |  [TEXT/MPS ]

  1. {------------------------------------------------------------------------------}
  2. {#}
  3. {#    Apple Macintosh Developer Technical Support}
  4. {#}
  5. {#    XTND-Capable, MultiFinder-Aware Simple Styled TextEdit Sample Application}
  6. {#}
  7. {#    XTEStyleSample}
  8. {#}
  9. {#    XTEStyleSample.p    -    Pascal Source}
  10. {#}
  11. {#    Copyright © 1989 Apple Computer, Inc.}
  12. {#    All rights reserved.}
  13. {#}
  14. {#    Versions:    1.0                        10/89}
  15. {#                2.0                        3/91}
  16. {#}
  17. {#    Components:    XTEStyleSample.p            March 29, 1991}
  18. {#                XTEStyleSampleGlue.a        March 29, 1991}
  19. {#                XTEStyleSample.r            March 29, 1991}
  20. {#                XTEStyleSample.h            March 29, 1991}
  21. {#                XTEStyleSample.make            March 29, 1991}
  22. {#}
  23. {#    XTEStyleSample is an example application that demonstrates how }
  24. {#    to initialize the commonly used toolbox managers, operate }
  25. {#    successfully under MultiFinder, handle desk accessories and }
  26. {#    create, grow, and zoom windows. Both styled and fundamental TextEdit }
  27. {#    toolbox calls and TextEdit autoscroll are demonstrated. It }
  28. {#    also shows how to create and maintain scrollbar controls as well}
  29. {#    as implementing a basic printing loop. In addition, it has the}
  30. {#    capability to import or export via XTND technology. Thus you can }
  31. {#    save to MacWrite, MS Word, etc. or Open WordPerfect, or other files}
  32. {#    for which you have translators available.}
  33. {#}
  34. {#    It does not by any means demonstrate all the techniques you }
  35. {#    need for a large application. In particular, XTEStyleSample does not }
  36. {#    cover exception handling, multiple windows/documents, }
  37. {#    sophisticated memory management, or undo. All of }
  38. {#    these are vital parts of a normal full-sized application.}
  39. {#}
  40. {#    This application is an example of the form of a Macintosh }
  41. {#    application; it is NOT a template. It is NOT intended to be }
  42. {#    used as a foundation for the next world-class, best-selling, }
  43. {#    600K application. A stick figure drawing of the human body may }
  44. {#    be a good example of the form for a painting, but that does not }
  45. {#    mean it should be used as the basis for the next Mona Lisa.}
  46. {#}
  47. {#    We recommend that you review this program, TEStyleSample, TESample or Sample before }
  48. {#    beginning a new application. XTEStyleSample is built from TEStyleSample, but}
  49. {#    has the added capability of importing and exporting through the XTND}
  50. {#    architecture. TESample is a simpler version of TEStyleSample}
  51. {#    without styles and Sample is a simple app. which doesn’t }
  52. {#    use TextEdit or the Control Manager.}
  53. {#}
  54. {------------------------------------------------------------------------------}
  55.  
  56.  
  57. PROGRAM XTEStyleSample;
  58.  
  59. {Segmentation strategy:}
  60. {}
  61. { This program consists of three segments. Main contains most of the code,}
  62. { including the MPW libraries, and the main program. Initialize contains}
  63. { code that is only used once, during startup, and can be unloaded after the}
  64. { program starts. %A5Init is automatically created by the Linker to initialize}
  65. { globals for the MPW libraries and is unloaded right away.}
  66.  
  67.  
  68. {SetPort strategy:}
  69. {}
  70. { Toolbox routines do not change the current port. In spite of this, in this}
  71. { program we use a strategy of calling SetPort whenever we want to draw or}
  72. { make calls which depend on the current port. This makes us less vulnerable}
  73. { to bugs in other software which might alter the current port (such as the}
  74. { bug (feature?) in many desk accessories which change the port on OpenDeskAcc).}
  75. { Hopefully, this also makes the routines from this program more self-contained,}
  76. { since they don't depend on the current port setting.}
  77.  
  78.  
  79. {Clipboard strategy: }
  80. {}
  81. { Under styled TextEdit, TECut and TECopy will write both the text and associated}
  82. { style information directly to the desk scrap as types 'TEXT' and 'styl'.}
  83. { Instead of using TEToScrap and TEFromScrap, a new routine TEStylPaste, will }
  84. { transfer the text and style from the desk scrap to the document. }
  85.  
  86. {$D+}
  87.  
  88.     USES
  89.         MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps, MacPrint, 
  90.         XTNDInterface, XTNDTextTranslator, XTNDPictTranslator, XTEFileIO;
  91.  
  92.     CONST
  93.  
  94.     {kMaxOpenDocuments is used to determine whether a new document can be opened}
  95. {     or created. We keep track of the number of open documents, and disable the}
  96. {     menu items that create a new document when the maximum is reached. If the}
  97. {     number of documents falls below the maximum, the items are enabled again.}
  98.         kMaxOpenDocuments = 10;
  99.  
  100.     {kMinDocDim is used to limit the minimum dimension of a window when GrowWindow}
  101. {    is called.}
  102.         kMinDocDim = 64;
  103.  
  104.     {kControlInvisible is used to 'turn off' controls (i.e., cause the control not}
  105. {    to be redrawn as a result of some Control Manager call such as SetCtlValue)}
  106. {    by being put into the contrlVis field of the record. kControlVisible is used}
  107. {    the same way to 'turn on' the control.}
  108.         kControlInvisible = 0;
  109.         kControlVisible = $FF;
  110.  
  111.     {kMaxTELength is an arbitrary number used to limit the length of text in the TERec}
  112. {    so that various errors won't occur from too many characters in the text.}
  113.         kMaxTELength = 32000;
  114.     (* what about that tech note I wrote? is this a valid check anymore? maw *)
  115.  
  116.     {kSysEnvironsVersion is passed to SysEnvirons to tell it which version of the}
  117. {     SysEnvRec we understand.}
  118.         kSysEnvironsVersion = 1;
  119.  
  120.     {kOSEvent is the event number of the suspend/resume and mouse-moved events sent}
  121. {     by MultiFinder. Once we determine that an event is an osEvent, we look at the}
  122. {     high byte of the message sent to determine which kind it is. To differentiate}
  123. {     suspend and resume events we check the resumeMask bit.}
  124.         kOSEvent = app4Evt;    { event used by MultiFinder }
  125.         kSuspendResumeMessage = 1;        { high byte of suspend/resume event message }
  126.         kResumeMask = 1;        { bit of message field for resume vs. suspend }
  127.         kMouseMovedMessage = $FA;        { high byte of mouse-moved event message }
  128.         kNoEvents = 0;        {no events mask}
  129.  
  130.     {kMinHeap - This is the minimum result from the following}
  131. {     equation:}
  132. {            }
  133. {            ORD(GetApplLimit) - ORD(ApplicZone)}
  134. {            }
  135. {     for the application to run. It will insure that enough memory will}
  136. {     be around for reasonable-sized scraps, FKEYs, etc. to exist with the}
  137. {     application, and still give the application some 'breathing room'.}
  138. {     To derive this number, we ran under a MultiFinder partition that was}
  139. {     our requested minimum size, as given in the 'SIZE' resource.}
  140.  
  141.         kMinHeap = 29 * 1024;
  142.  
  143.     {kMinSpace - This is the minimum result from PurgeSpace, when called}
  144. {     at initialization time, for the application to run. This number acts}
  145. {     as a double-check to insure that there really is enough memory for the}
  146. {     application to run, including what has been taken up already by}
  147. {     pre-loaded resources, the scrap, code, and other sundry memory blocks.}
  148.  
  149.         kMinSpace = 20 * 1024;
  150.  
  151.     {kExtremeNeg and kExtremePos are used to set up wide open rectangles and regions.}
  152.         kExtremeNeg = -32768;
  153.         kExtremePos = 32767 - 1;    { required for old region bug }
  154.  
  155.     {kTESlop provides some extra security when pre-flighting edit commands.}
  156.         kTESlop = 1024;
  157.  
  158.     { The following constants are all menu and item IDs corresponding to their resources }
  159.  
  160.         mApple = 128;                { Apple menu }
  161.         iAbout = 1;
  162.  
  163.         mFile = 129;                { File menu }
  164.         iNew = 1;
  165.         iOpen = 2;                { Added for XTEStyleSample }
  166.         iClose = 4;
  167.         iSave = 5;                { Added for XTEStyleSample }
  168.         iSaveAs = 6;                { Added for XTEStyleSample }
  169.         iPageSetup = 9;                { Added for TEStyleSample }
  170.         iPrint = 10;                { Added for TEStyleSample }
  171.         iQuit = 12;
  172.  
  173.         mEdit = 130;                { Edit menu }
  174.         iUndo = 1;
  175.         iCut = 3;
  176.         iCopy = 4;
  177.         iPaste = 5;
  178.         iClear = 6;
  179.         iSelectAll = 8;                { Added for XTEStyleSample }
  180.  
  181.         mFont = 131;                { Font menu-added for XTEStyleSample }
  182.  
  183.         mFontSize = 132;                { Font size menu-added for XTEStyleSample }
  184.         iNine = 1;
  185.         iTen = 2;
  186.         iTwelve = 3;
  187.         iFourteen = 4;
  188.         iEighteen = 5;
  189.         iTwoFour = 6;
  190.         iOther = 7;
  191.  
  192.         mStyle = 133;                { Style menu-added for XTEStyleSample }
  193.         iPlain = 1;
  194.         iBold = 3;
  195.         iItalic = 4;
  196.         iUnderline = 5;
  197.         iOutline = 6;
  198.         iShadow = 7;
  199.  
  200.     {kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  201.         kDITop = $0050;
  202.         kDILeft = $0070;
  203.  
  204.         kStyleResType = 'styl';
  205.  
  206.         kNewWindowOffset = 20;
  207.         kWndPosResID = 6;
  208.  
  209.         kTransVersion = 2;        { this is the translator version we want }
  210.  
  211.     TYPE
  212.         WindowPosHandle = ^WindowPosPtr;
  213.         WindowPosPtr = ^WindowPosRec;
  214.         WindowPosRec = RECORD
  215.                 wndPos: Point;
  216.                 wndSize: Point;
  217.                 selStart, selEnd, scrollVal, scrollMax: INTEGER;
  218.             END;
  219.  
  220.     VAR
  221.     {The "g" prefix is used to emphasize that a variable is global.}
  222.         gMac: SysEnvRec;    { set up by Initialize }
  223.         gHasWaitNextEvent: BOOLEAN;        { set up by Initialize }
  224.         gInBackground: BOOLEAN;        { maintained by Initialize and DoEvent }
  225.         gFirstMyDlgCall: BOOLEAN;        { maintained by Initialize, DoNew, DoOpen, and DoCloseWindow }
  226.  
  227.     {New globals to support printing and style selection }
  228.         gTxStyle: TextStyle;    { holds style selected, plain default, maintained by DoMenuCommand }
  229.         gFontName: Str255;        { name of font selected, app font default, maintained by DoMenuCommand }
  230.         gFontID: INTEGER;        { ID of font selected, app font default, maintained by DoMenuCommand }
  231.         gFontSize: LONGINT;        { font size selected, 12 pt default, maintained by DoMenuCommand }
  232.         gPrinterRecord: THPrint;        { print handle, maintained by printText }
  233.         gPrinterPort: TPPrPort;        { pointer to Print Manager's GrafPort }
  234.  
  235.  
  236.     (*----- windows --------------*)
  237.         gGrayRgn: RgnHandle;
  238.         gDragRect: Rect;            (*bounds rect for dragging window*)
  239.         gSizeRect: Rect;            (*limits for resizing window*)
  240.         gInitWndPos: Point;        (*initial window pos for saved files*)
  241.         gInitScrollVal: INTEGER;
  242.         gInitScrollMax: INTEGER;
  243.         gTotalWindows: longInt;        (* Amount to offset new windows by *)
  244.  
  245.  
  246.     (*------- import ----------*)
  247.         gSaveSelected: INTEGER;
  248.         gxtErr, gError: OSErr;
  249.         gTransVersion: INTEGER;
  250.         gTransList: TransDescrHandle;
  251.  
  252.     { Get/Put Import/Export File Routine Declarations }
  253. { PROCEDURE CallFilter(pAddress: ProcPtr; pParams: Ptr); }
  254.  
  255. {$S Initialize}
  256.     FUNCTION TrapAvailable (tNumber: INTEGER; tType: TrapType): BOOLEAN;
  257.  
  258. {Check to see if a given trap is implemented. This is only used by the}
  259. { Initialize routine in this program, so we put it in the Initialize segment.}
  260. { The recommended approach to see if a trap is implemented is to see if}
  261. { the address of the trap routine is the same as the address of the}
  262. { Unimplemented trap.}
  263. {Needs to be called after call to SysEnvirons so that it can check}
  264. { if a ToolTrap is out of range of a pre-MacII ROM.}
  265. {$IFC UNDEFINED MPW}
  266.         CONST
  267.             _Unimplemented = $A89F;
  268. {$ENDC}
  269.     BEGIN
  270.         IF (tType = ToolTrap) & (gMac.machineType > envMachUnknown) & (gMac.machineType < envMacII) THEN BEGIN        {it's a 512KE, Plus, or SE}
  271.             tNumber := BAND(tNumber, $03FF);
  272.             IF tNumber > $01FF THEN                            {which means the tool traps}
  273.                 tNumber := _Unimplemented;                    {only go to $01FF}
  274.         END;
  275.         TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(_Unimplemented);
  276.     END; {TrapAvailable}
  277.  
  278. {$S Main}
  279.     FUNCTION GetNewFontSize: INTEGER;
  280. {  Display an alert that lets the user choose an unlisted font size }
  281.         CONST
  282.             rFontSelect = 130;
  283.             kSizeItem = 4;
  284.         VAR
  285.             itemHit, theType, oldSize: INTEGER;
  286.             message: Str255;
  287.             sizeDlg: DialogPtr;
  288.             itemHdl: Handle;
  289.             itembox: Rect;
  290.             sizeNum: LONGINT;
  291.     BEGIN { GetNewFontSize }
  292.         oldSize := gFontSize;
  293.         sizeDlg := GetNewDialog(rFontSelect, NIL, WindowPtr(-1));
  294.         IF sizeDlg <> NIL THEN BEGIN
  295.             NumToString(gFontSize, message);
  296.             GetDItem(sizeDlg, kSizeItem, theType, itemHdl, itembox);
  297.             SetIText(itemHdl, message);
  298.             ShowWindow(sizeDlg);
  299.             REPEAT
  300.                 ModalDialog(NIL, itemHit);
  301.             UNTIL (itemHit = OK) OR (itemHit = Cancel);
  302.             IF itemHit = OK THEN BEGIN
  303.                 GetDItem(sizeDlg, kSizeItem, theType, itemHdl, itembox);
  304.                 GetIText(itemHdl, message);
  305.                 StringToNum(message, sizeNum);
  306.                 GetNewFontSize := sizeNum;
  307.             END
  308.             ELSE
  309.                 GetNewFontSize := oldSize;
  310.             DisposDialog(sizeDlg);
  311.         END
  312.         ELSE
  313.             GetNewFontSize := oldSize;
  314.     END; { GetNewFontSize }
  315.  
  316. {$S Main}
  317.     PROCEDURE AdjustTE (window: WindowPtr);
  318. {    Scroll the TERec around to match up to the potentially updated scrollbar}
  319. {    values. This is really useful when the window resizes such that the}
  320. {    scrollbars become inactive and the TERec had been previously scrolled. }
  321.         VAR
  322.             value: INTEGER;
  323.  
  324.     BEGIN { AdjustTE }
  325.         WITH DocumentPeek(window)^ DO BEGIN
  326.             TEScroll((docTE^^.viewRect.left - docTE^^.destRect.left) - GetCtlValue(docHScroll), (docTE^^.viewRect.top - docTE^^.destRect.top) - GetCtlValue(docVScroll), docTE);
  327.         END; { with }
  328.     END; { AdjustTE }
  329.  
  330. {$S Main}
  331.     PROCEDURE AdjustScrollSizes (window: WindowPtr);
  332.  
  333. {    Re-calculate the position and size of the viewRect and the scrollbars.}
  334. {     kScrollTweek compensates for off-by-one requirements of the scrollbars}
  335. {    to have borders coincide with the growbox. }
  336.  
  337.         VAR
  338.             teRect: Rect;
  339.  
  340.     BEGIN { AdjustScrollSizes }
  341.         GetTERect(window, teRect); {start with teRect}
  342.         WITH DocumentPeek(window)^, window^.portRect DO BEGIN
  343.             docTE^^.viewRect := teRect;
  344.  
  345.         { AdjustViewRect(docTE) was removed--no longer needed }
  346.  
  347.             MoveControl(docVScroll, right - kScrollbarAdjust, -1);
  348.             SizeControl(docVScroll, kScrollbarWidth, (bottom - top) - (kScrollbarAdjust - kScrollTweek));
  349.             MoveControl(docHScroll, -1, bottom - kScrollbarAdjust);
  350.             SizeControl(docHScroll, (right - left) - (kScrollbarAdjust - kScrollTweek), kScrollbarWidth);
  351.         END; { with }
  352.     END; { AdjustScrollSizes }
  353.  
  354. {$S Main}
  355.     PROCEDURE AdjustScrollbars (window: WindowPtr; needsResize: BOOLEAN);
  356.  
  357. {    Turn off the controls by jamming a zero into their contrlVis fields }
  358. {    (HideControl erases them and we don't want that). If the controls are to }
  359. {    be resized as well, call the procedure to do that, then call the procedure }
  360. {    to adjust the maximum and current values. Finally re-enable the controls}
  361. {    by jamming a $FF in their contrlVis fields. }
  362.  
  363.         VAR
  364.             oldMax, oldVal: INTEGER;
  365.  
  366.     BEGIN { AdjustScrollbars }
  367.         WITH DocumentPeek(window)^ DO BEGIN
  368.             docVScroll^^.contrlVis := kControlInvisible; { turn them off }
  369.             docHScroll^^.contrlVis := kControlInvisible;
  370.             IF needsResize THEN                            { move and size if needed }
  371.                 AdjustScrollSizes(window);
  372.             AdjustScrollValues(window, NOT needsResize); { fool with max and current value }
  373.         { Now, restore visibility in case we never had to ShowControl during adjustment }
  374.             docVScroll^^.contrlVis := kControlVisible; { turn them on }
  375.             docHScroll^^.contrlVis := kControlVisible;
  376.         END;
  377.     END; { AdjustScrollbars }
  378.  
  379. {$S Main}
  380. {$PUSH}
  381.  {$Z+}
  382.     PROCEDURE PascalClikLoop;
  383.  
  384. {    Gets called from our assembly language routine, AsmClikLoop, which is in}
  385. {     turn called by the TEClick toolbox routine. Saves the windows clip region,}
  386. {     sets it to the portRect, adjusts the scrollbar values to match the TE scroll}
  387. {     amount, then restores the clip region. }
  388.  
  389.         VAR
  390.             window: WindowPtr;
  391.             region: RgnHandle;
  392.  
  393.     BEGIN { PascalClikLoop }
  394.         window := FrontWindow;
  395.         region := NewRgn;
  396.         GetClip(region); { save the old clip }
  397.         ClipRect(window^.portRect); { set the new clip }
  398.         AdjustScrollValues(window, TRUE); { pass TRUE for canRedraw }
  399.         SetClip(region); { restore the old clip }
  400.         DisposeRgn(region);
  401.     END; { PascalClikLoop }
  402. {$POP}
  403.  
  404. {$S Main}
  405. {$PUSH}
  406.  {$Z+}
  407.     FUNCTION GetOldClikLoop: ProcPtr;
  408.  
  409. {    Gets called from our assembly language routine, AsmClikLoop, which is in}
  410. {    turn called by the TEClick toolbox routine. It returns the address of the}
  411. {    default clikLoop routine that was put into the TERec by TEAutoView to}
  412. {    AsmClikLoop so ¢t it can call it. }
  413.  
  414.     BEGIN { GetOldClikLoop }
  415.         GetOldClikLoop := DocumentPeek(FrontWindow)^.docClik;
  416.     END; { GetOldClikLoop }
  417. {$POP}
  418.  
  419.     PROCEDURE AsmClikLoop;
  420.     EXTERNAL;
  421.  
  422. {    A reference to our assembly language routine that gets attached to the clikLoop}
  423. {    field of our TE record. }
  424.  
  425. (*------------------------------------------------------------------------------*)
  426. {$S Main}
  427.     PROCEDURE Set_init_position;
  428.     BEGIN { Set_init_position }
  429.         gSelStart := 0;
  430.         gSelEnd := 0;
  431.         gInitWndPos.h := (kNewWindowOffset * gNumDocuments) MOD 172 + 10;
  432.         gInitWndPos.v := (kNewWindowOffset * gNumDocuments) MOD 172 + 45;
  433.         gInitWndSize.h := 400;
  434.         gInitWndSize.v := 300;
  435.         gInitScrollVal := 0;
  436.         gInitScrollMax := 0;
  437.     END;    (* Set_init_position *)
  438.  
  439. (*------------------------------------------------------------------------------*)
  440. {$S Main}
  441.     PROCEDURE Read_position (prevWDRefNum: INTEGER; prevFileName: Str255);
  442.         VAR
  443.             refNum: INTEGER;
  444.             prevPosHdl: WindowPosHandle;
  445.     BEGIN    { Read_position }
  446.         Set_init_position;
  447.  
  448.         refNum := OpenRFPerm(prevFileName, prevWDRefNum, fsRdPerm);
  449.         IF (refNum <> -1) THEN BEGIN
  450.         (* read in window position and selection range *)
  451.             prevPosHdl := WindowPosHandle(Get1Resource(kStyleResType, kWndPosResID));
  452.             IF prevPosHdl <> NIL THEN BEGIN
  453.                 HNoPurge(Handle(prevPosHdl));
  454.                 IF (PtInRgn(prevPosHdl^^.wndPos, gGrayRgn)) THEN BEGIN
  455.                     gSelStart := prevPosHdl^^.selStart;
  456.                     gSelEnd := prevPosHdl^^.selEnd;
  457.                     gInitWndPos := prevPosHdl^^.wndPos;
  458.                     gInitWndSize := prevPosHdl^^.wndSize;
  459.                     gInitScrollVal := prevPosHdl^^.scrollVal;
  460.                     gInitScrollMax := prevPosHdl^^.scrollMax;
  461.                 END;
  462.             END;
  463.         END;
  464.         CloseResFile(refNum);
  465.     END;    (* Read_position *)
  466.  
  467. (*------------------------------------------------------------------------------*)
  468. {$S Main}
  469.     PROCEDURE ReadFile (myFType: INTEGER; vRefNum: INTEGER; fName: Str255);
  470.         VAR
  471.             error: OSErr;
  472.             fileNumber: INTEGER;
  473.             textLength: LongInt;
  474.             buffPtr: Ptr;
  475.             tempRect: Rect;
  476.     BEGIN
  477.         Read_position(vRefNum, fName);
  478.         DoNew;
  479.         SetWTitle(gTheActiveWindow, fName);    (*set correct window title*)
  480.         DocumentPeek(gTheActiveWindow)^.WDRefNum := vRefNum;
  481.         DocumentPeek(gTheActiveWindow)^.fileName := fName;
  482.  
  483.         error := FSOpen(fName, vRefNum, fileNumber);       (*open disk file*)
  484.         error := GetEOF(fileNumber, textLength);            (*find length of data in file*)
  485.         IF (textLength > $7FFF) THEN
  486.             textLength := $7FFF;  (*only read first 32k of text*)
  487.         error := SetFPos(fileNumber, fsFromStart, 0); (*set mark at beginning of file*)
  488.         buffPtr := NewPtr(textLength);
  489.         error := FSRead(fileNumber, textLength, buffPtr);
  490.         error := FSClose(fileNumber);                                 (*close file for safety*)
  491.         TESetText(buffPtr, textLength, gTextH);
  492.         DisposPtr(buffPtr);                                                (*garbage collect*)
  493.  
  494.         TECalText(gTextH);                                  (*calc line starts in TERecord*)
  495.         TESetSelect(gSelStart, gSelEnd, gTextH);                         (*Set insertion point*)
  496.         SetRect(tempRect, 0, 0, 0, 0);
  497.         ClipRect(tempRect);                   (* Close clipping region to remove flicker *)
  498.         AdjustScrollValues(gTheActiveWindow, TRUE);
  499.         AdjustTE(gTheActiveWindow);
  500.         ClipRect(gTheActiveWindow^.portRect);
  501.         InvalRect(gTheActiveWindow^.portRect);
  502.     END;    (* ReadFile *)
  503.  
  504.     FUNCTION MyDlgHook (theItem: INTEGER; theDialog: DialogPtr; CFP: SFParamBlock; VAR changedFlag: Boolean; unused: LongInt): INTEGER;
  505.     BEGIN
  506.         IF theItem = 6 THEN
  507.             IF gFirstMyDlgCall THEN BEGIN
  508.                 CFP.AllowFlags := allowText;
  509.                 changedFlag := TRUE;
  510.                 gFirstMyDlgCall := FALSE;
  511.             END;
  512.         MyDlgHook := theItem;
  513.     END;    (* MyDlgHook *)
  514.  
  515. {$S Main}
  516.     PROCEDURE BigBadError (error: INTEGER);
  517.     BEGIN
  518.         AlertUser(error,0);
  519.         ExitToShell;
  520.     END;
  521.  
  522. {$S Initialize}
  523.     PROCEDURE Initialize;
  524.  
  525. {    Set up the whole world, including global variables, Toolbox managers,}
  526. {     menus, and a single blank document.}
  527.  
  528. {If an error is detected, instead of merely doing an ExitToShell,}
  529. { which leaves the user without much to go on, we call AlertUser, which puts}
  530. { up a simple alert that just says an error occurred and then calls ExitToShell.}
  531. { Since there is no other cleanup needed at this point if an error is detected,}
  532. { this form of error- handling is acceptable. If more sophisticated error recovery}
  533. { is needed, an exception mechanism, such as is provided by Signals, can be used.}
  534. CONST
  535.         { ———— Defines for XTND resources ———— }
  536.         clarisNames            = 25003;    { Claris names STR# resource }
  537.         clarisFolder         = 1;
  538.         xtndNames            = 25004;    { XTND names STR# resource }
  539.         clarisTranslators    = 1;
  540.         xtndSystem            = 2;
  541. VAR
  542.     menuBar: Handle;
  543.     total, contig: LongInt;
  544.     ignoreResult: BOOLEAN;
  545.     event: EventRecord;
  546.     count, ignoreError: INTEGER;
  547.     XTNDSystemName, 
  548.     ClarisFolderName: Str255;
  549.  
  550. BEGIN { Initialize }
  551.         gInBackground := FALSE;
  552.  
  553.         InitGraf(@thePort);
  554.         InitFonts;
  555.         InitWindows;
  556.         InitMenus;
  557.         TEInit;
  558.         InitDialogs(NIL);
  559.         InitCursor;
  560.  
  561.         FOR count := 1 TO 3 DO
  562.             ignoreResult := EventAvail(everyEvent, event);
  563.         ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
  564.         IF gMac.machineType < 0 THEN
  565.             BigBadError(eWrongMachine);
  566.         gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  567.  
  568.         IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN
  569.             BigBadError(eSmallSize);
  570.         PurgeSpace(total, contig);
  571.         IF total < kMinSpace THEN
  572.             IF UnloadScrap <> noErr THEN
  573.                 BigBadError(eNoMemory)
  574.             ELSE BEGIN
  575.                 PurgeSpace(total, contig);
  576.                 IF total < kMinSpace THEN
  577.                     BigBadError(eNoMemory);
  578.             END; { if }
  579.  
  580.         menuBar := GetNewMBar(rMenuBar); { read menus into menu bar }
  581.         IF menuBar = NIL THEN
  582.             BigBadError(eNoMemory);
  583.         SetMenuBar(menuBar); { install menus }
  584.         DisposHandle(menuBar);
  585.         AddResMenu(GetMHandle(mApple), 'DRVR');    { add DA names to Apple menu }
  586.         AddResMenu(GetMHandle(mFont), 'FONT'); { add Font names to Font Menu }
  587.         DrawMenuBar;
  588.         gNumDocuments := 0;
  589.  
  590.     { do other initialization here }
  591.     { set up printer stuff-this will allow the default pageSetup parameters to be used, so if}
  592. {      the used decides to print with out using pageSetup everything will be okay }
  593.  
  594.         gPrinterRecord := THPrint(NewHandle(SizeOF(TPrint))); {allocate a print record}
  595.         IF gPrinterRecord <> NIL THEN BEGIN {if we're successful then setup the default settings}
  596.             PrOpen; {open the record }
  597.             PrintDefault(gPrinterRecord); { load in default settings }
  598.             PrClose; { close it up }
  599.         END; { if }
  600.  
  601.         { one-time initialization of the XTND Library… }
  602.         GetIndString(XTNDSystemName, xtndNames, xtndSystem);
  603.         GetIndString(ClarisFolderName, clarisNames, clarisFolder);
  604.     
  605.         gxtErr := XTNDInitTranslators(kTransVersion, XTNDSystemName, ClarisFolderName);
  606.         IF gxtErr <> noErr THEN BEGIN
  607.             AlertUser(eNoXTND,gxtErr);
  608.             gXTNDAvail := FALSE;
  609.         END
  610.         ELSE BEGIN
  611.             gXTNDAvail := TRUE;
  612.             gMyFileType[1].Version := 2;
  613.             gMyFileType[1].TranslatorType := 'FLTI';
  614.             gMyFileType[1].CodeResID := 0;
  615.             gMyFileType[1].FDIFResID := -1;
  616.             gMyFileType[1].NumVersBytes := 0;
  617.             gMyFileType[1].PathLength := 0;
  618.             gMyFileType[1].Flags := 0;
  619.             gMyFileType[1].NumMatches := 1;
  620.             gMyFileType[1].Matches[0].DocCreator := 'XTND';
  621.             gMyFileType[1].Matches[0].DocType := 'TEXT';
  622.             gMyFileType[1].Matches[0].ExactMatch := FALSE;
  623.             gMyFileType[1].Matches[0].creatorAndTypeMask := 0;
  624.             gMyFileType[1].Name := 'Text';
  625.             Load_stored := 1;
  626.             Save_stored := 1;
  627.         END;
  628.  
  629.         DoNew; { create a single empty document }
  630.     END; {Initialize}
  631.  
  632. {$S Main}
  633.     PROCEDURE PrintText (hTE: TEHandle);
  634.  
  635. {    Prints the edit record. Opens a printer port, calculates the numbers of lines}
  636. {    per page (it may be different for each page depending on the the text styles) and}
  637. {    then calls TEUpdate for the page, scroll a page and TEUpdate, etc. }
  638.  
  639.         CONST
  640.             Margins = 20;         { page margins }
  641.  
  642.         VAR
  643.             totalLines: INTEGER;    { number of lines in text }
  644.             rView: Rect;        { viewRect for TERect }
  645.             oldPort: grafPtr;    { hold original grafPtr }
  646.             oldView: Rect;        { hold original viewRect }
  647.             oldDest: Rect;        { hold original destRect }
  648.             totalHeight: INTEGER;    { lineHeight for TERec }
  649.             currentLine: INTEGER;    { what line are we on }
  650.             scrollAmount: INTEGER;    { how much we scroll by }
  651.             zeroRect: Rect;        { 0,0,0,0 rect used in clipRect }
  652.  
  653.             thePrinterStatus: TPrStatus; { printer status }
  654.             openPrintManager: BOOLEAN;    { flag if print manager can be opened okay }
  655.             abort: BOOLEAN;    { flag if cmd-period is hit to exit routine }
  656.             viewHeight: INTEGER;    { temp that has the viewRect height+1 to test conditions }
  657.  
  658.     BEGIN { PrintText }
  659.         OpenPrintManager := FALSE; {printer not open yet}
  660.         IF gPrinterRecord <> NIL THEN BEGIN { do we have a legitimate record?}
  661.             PrOpen; {open mr. print record if okay}
  662.             IF PrJobDialog(gPrinterRecord) THEN BEGIN {bring up job dialog}
  663.                 GetPort(oldPort); { save the old stuff to restore later }
  664.                 oldView := hTE^^.viewRect;
  665.                 oldDest := hTE^^.destRect;
  666.                 gPrinterPort := PrOpenDoc(gPrinterRecord, NIL, NIL);
  667.                 OpenPrintManager := (PrError = noErr);
  668.             END; { if }
  669.         END; { if }
  670.  
  671.         IF OpenPrintManager THEN BEGIN
  672.             SetPort(grafPtr(gPrinterPort)); { printer port is now the current port }
  673.             SetRect(zeroRect, 0, 0, 0, 0);
  674.  
  675.             rView := gPrinterRecord^^.PrInfo.rPage; { get the size of the page rectangle }
  676.             InsetRect(rView, Margins, Margins);  { adjust it for the margins }
  677.             hTE^^.inPort := GrafPtr(gPrinterPort); { force TE to look at the printer port }
  678.             hTE^^.destRect := rView;
  679.             hTE^^.viewRect := rView; { set new view and dest rects to the TERec }
  680.             TECalText(hTE); { recalculate our lineStarts array with the new rects }
  681.             totalLines := hTE^^.nLines; { get the number of lines in the newly sized TERec }
  682.             totalHeight := TEGetHeight(totalLines, 0, hTE);
  683.             hTE^^.destRect.bottom := hTE^^.destRect.top + totalHeight; { how tall our destRect is }
  684.  
  685.             abort := FALSE;
  686.             currentLine := 1; { TextEdit sez that TEGetHeight is 1 not 0 based }
  687.  
  688.             WHILE (NOT (abort) AND (currentLine <= totalLines)) DO BEGIN
  689.                 PrOpenPage(gPrinterPort, NIL);
  690.                 scrollAmount := 0;
  691.                 ClipRect(gPrinterRecord^^.PrInfo.rPage); { Open clipping so text will be drawn }
  692.  
  693.                 viewHeight := hTE^^.viewRect.bottom - hTE^^.viewRect.top + 1;
  694.  
  695.             { figure out how many lines there are per page }
  696.                 WHILE (((scrollAmount + TEGetHeight(currentLine, currentLine, hTE)) <= viewHeight) AND (currentLine <= totalLines)) DO BEGIN
  697.                     scrollAmount := scrollAmount + TEGetHeight(currentLine, currentLine, hTE);
  698.                     currentLine := currentLine + 1;
  699.                 END; { while }
  700.  
  701.                 hTE^^.viewRect.bottom := scrollAmount + Margins; { Add margins since top has a margin }
  702.                 TEDeactivate(hTE); { Deactive the edit record so we don't print the cursor or selection range }
  703.                 TEUpdate(hTE^^.viewRect, hTE); { print the page }
  704.                 ClipRect(zeroRect); { Close clipping so that TEScroll doesn't redraw the text }
  705.                 TEScroll(0, -scrollAmount, hTE); { scroll the page so we can print the next one }
  706.                 hTE^^.viewRect.bottom := rView.bottom; { reset bottom to full page }
  707.  
  708.                 IF prError = iPrAbort THEN
  709.                     abort := TRUE;
  710.                 PrClosePage(gPrinterPort); { close everything up }
  711.             END; { while }
  712.  
  713.             PrCloseDoc(gPrinterPort);
  714.             IF (gPrinterRecord^^.prJob.bJDocLoop = bSpoolLoop) AND (PrError = noErr) THEN
  715.                 PrPicFile(gPrinterRecord, NIL, NIL, NIL, thePrinterStatus);
  716.             PrClose;
  717.             SetPort(oldPort);
  718.             hTE^^.inPort := oldPort;
  719.             hTE^^.viewRect := oldView; { restore the old stuff when we are done }
  720.             hTE^^.destRect := oldDest;
  721.             TEUpdate(hTE^^.viewRect, hTE); { update everything after resetting the port }
  722.         END; { if }
  723.     END; { PrintText }
  724.  
  725. {$S Main}
  726.     PROCEDURE Terminate;
  727.  
  728. {    Clean up the application and exit. We close all of the windows so that}
  729. {    they can update their documents, if any. }
  730.  
  731.         VAR
  732.             aWindow: WindowPtr;
  733.             closed: BOOLEAN;
  734.  
  735.     BEGIN { Terminate }
  736.         closed := TRUE;
  737.         REPEAT
  738.             aWindow := FrontWindow; { get the current front window }
  739.             IF aWindow <> NIL THEN
  740.                 closed := DoCloseWindow(aWindow);    { close this window }
  741.         UNTIL (NOT closed) | (aWindow = NIL); { do all windows }
  742.         IF closed THEN
  743.             ExitToShell; { exit if no cancellation }
  744.     END; { Terminate }
  745.  
  746. {$S Main}
  747.     PROCEDURE AdjustMenus;
  748.  
  749.         VAR
  750.             window: WindowPtr;
  751.             menu: MenuHandle;
  752.             offset: LONGINT;
  753.             undo: BOOLEAN;    { flag to enable/disable undo command }
  754.             cutCopyClear: BOOLEAN;    { flag to enable/disable editing commands }
  755.             paste: BOOLEAN;
  756.             selectAll: BOOLEAN;
  757.  
  758.             doPrint: BOOLEAN;    { flag to enable/disable printing item }
  759.  
  760.             te: TEHandle;    { local te handle }
  761.             mode: INTEGER;    { current style }
  762.  
  763.     BEGIN
  764.         window := FrontWindow;
  765.  
  766.         menu := GetMHandle(mFile);
  767.         IF gNumDocuments < kMaxOpenDocuments THEN BEGIN
  768.             EnableItem(menu, iNew);{ New is enabled when we can open more documents }
  769.             EnableItem(menu, iOpen);{ Open is enabled when we can open more documents }
  770.         END
  771.         ELSE BEGIN
  772.             DisableItem(menu, iOpen);
  773.             DisableItem(menu, iNew);
  774.         END;
  775.  
  776.         IF window <> NIL THEN BEGIN { Close/Save are enabled when there is a window to close }
  777.             EnableItem(menu, iClose);
  778.             EnableItem(menu, iSave);
  779.             EnableItem(menu, iSaveAs);
  780.         END
  781.         ELSE BEGIN
  782.             DisableItem(menu, iClose);
  783.             DisableItem(menu, iSave);
  784.             DisableItem(menu, iSaveAs);
  785.         END;
  786.  
  787.         menu := GetMHandle(mEdit);
  788.         undo := FALSE;
  789.         cutCopyClear := FALSE;
  790.         paste := FALSE;
  791.         selectAll := FALSE;
  792.         doPrint := FALSE;
  793.  
  794.         IF IsDAWindow(window) THEN BEGIN
  795.             undo := TRUE; { all editing is enabled for DA windows }
  796.             cutCopyClear := TRUE;
  797.             paste := TRUE;
  798.             selectAll := TRUE;
  799.         END
  800.         ELSE IF IsAppWindow(window) THEN BEGIN
  801.             WITH DocumentPeek(window)^.docTE^^ DO
  802.                 IF selStart < selEnd THEN BEGIN
  803.                     cutCopyClear := TRUE;
  804.                 END; { if }
  805.                 { Cut, Copy, and Clear is enabled for app. windows with selections }
  806.             IF GetScrap(NIL, 'TEXT', offset) > 0 THEN
  807.                 paste := TRUE; { Paste is enabled for app. windows }
  808.  
  809.             selectAll := TRUE;
  810.             doPrint := TRUE;
  811.  
  812.             mode := doFace;
  813.             menu := GetMHandle(mStyle);
  814.             IF TEContinuousStyle(mode, gTxStyle, DocumentPeek(window)^.docTE) THEN BEGIN
  815.                 CheckItem(menu, iPlain, gTxStyle.tsface = []);
  816.                 CheckItem(menu, iBold, bold IN gTxStyle.tsFace);
  817.                 CheckItem(menu, iItalic, italic IN gTxStyle.tsFace);
  818.                 CheckItem(menu, iUnderline, underline IN gTxStyle.tsFace);
  819.                 CheckItem(menu, iOutline, outline IN gTxStyle.tsFace);
  820.                 CheckItem(menu, iShadow, shadow IN gTxStyle.tsFace);
  821.             END
  822.             ELSE BEGIN
  823.                 CheckItem(menu, iPlain, FALSE);
  824.                 CheckItem(menu, iBold, FALSE);
  825.                 CheckItem(menu, iItalic, FALSE);
  826.                 CheckItem(menu, iUnderline, FALSE);
  827.                 CheckItem(menu, iOutline, FALSE);
  828.                 CheckItem(menu, iShadow, FALSE);
  829.             END; { if }
  830.  
  831.         END; { if }
  832.         menu := GetMHandle(mEdit);
  833.  
  834.         IF undo THEN
  835.             EnableItem(menu, iUndo)
  836.         ELSE
  837.             DisableItem(menu, iUndo);
  838.  
  839.         IF cutCopyClear THEN BEGIN
  840.             EnableItem(menu, iCut);
  841.             EnableItem(menu, iCopy);
  842.             EnableItem(menu, iClear);
  843.         END
  844.         ELSE BEGIN
  845.             DisableItem(menu, iCut);
  846.             DisableItem(menu, iCopy);
  847.             DisableItem(menu, iClear);
  848.         END; { if }
  849.  
  850.  
  851.         IF paste THEN
  852.             EnableItem(menu, iPaste)
  853.         ELSE
  854.             DisableItem(menu, iPaste);
  855.  
  856.         IF selectAll THEN
  857.             EnableItem(menu, iSelectAll)
  858.         ELSE
  859.             DisableItem(menu, iSelectAll);
  860.  
  861.  
  862.         menu := GetMHandle(mFile);
  863.         IF doPrint THEN BEGIN
  864.             EnableItem(menu, iPageSetup);
  865.             EnableItem(menu, iPrint);
  866.         END
  867.         ELSE BEGIN
  868.             DisableItem(menu, iPageSetup);
  869.             DisableItem(menu, iPrint);
  870.         END; { if }
  871.  
  872.     END; { AdjustMenus }
  873.  
  874. {$S Main}
  875.     PROCEDURE DoMenuCommand (menuResult: LONGINT);
  876.  
  877. {    This is called when an item is chosen from the menu bar (after calling}
  878. {    MenuSelect or MenuKey). It does the right thing for each command. }
  879.  
  880.         VAR
  881.             menuID, menuItem: INTEGER;
  882.             itemHit, daRefNum: INTEGER;
  883.             daName: Str255;
  884.  
  885.             tempStr: Str255;
  886.             menu: MenuHandle;
  887.             anIntPtr: ^INTEGER;
  888.  
  889.             ignoreResult, saveErr: OSErr;
  890.             handledByDA: BOOLEAN;
  891.             te: TEHandle;
  892.             window: WindowPtr;
  893.             ignore: BOOLEAN;
  894.             aHandle: Handle;
  895.             oldSize, newSize: LONGINT;
  896.             total, contig: LONGINT;
  897.  
  898.  
  899.     BEGIN
  900.         window := FrontWindow;
  901.         menuID := HiWrd(menuResult); { use built-ins (for efficiency)... }
  902.         menuItem := LoWrd(menuResult); { to get menu item number and menu number }
  903.         te := DocumentPeek(window)^.docTE;
  904.  
  905.         CASE menuID OF
  906.  
  907.             mApple: 
  908.                 CASE menuItem OF
  909.                     iAbout:                {bring up alert for About}
  910.                         itemHit := Alert(rAboutAlert, NIL);
  911.                     OTHERWISE
  912.                         BEGIN        { all non-About items in this menu are DAs }
  913.                         GetItem(GetMHandle(mApple), menuItem, daName);
  914.                         daRefNum := OpenDeskAcc(daName);
  915.                     END; { otherwise }
  916.                 END; { case }
  917.  
  918.             mFile: 
  919.                 CASE menuItem OF
  920.                     iNew: 
  921.                         DoNew;
  922.                     iOpen: 
  923.                         BEGIN
  924.                         SetCursor(GetCursor(watchCursor)^^);
  925.                         DoOpen;
  926.                     END;
  927.  
  928.                     iClose: 
  929.                         ignore := DoCloseWindow(window);
  930.  
  931.                     iSave: 
  932.                         DoSave(FALSE);
  933.  
  934.                     iSaveAs: 
  935.                         DoSave(TRUE);
  936.  
  937.                     iPageSetup: 
  938.                         BEGIN
  939.                         PrOpen;
  940.                         IF PrError = noErr THEN
  941.                             ignore := PrStlDialog(gPrinterRecord);
  942.                         PrClose;
  943.                     END; { iPageSetup }
  944.                     iPrint: 
  945.                         PrintText(te);
  946.                     iQuit: 
  947.                         Terminate;
  948.                 END; { case }
  949.  
  950.             mEdit: 
  951.                 BEGIN                { call SystemEdit for DA editing & MultiFinder }
  952.                 IF NOT SystemEdit(menuItem - 1) THEN BEGIN
  953.                     CASE menuItem OF
  954.  
  955.                         iCut: 
  956.                             BEGIN
  957.                             IF ZeroScrap = noErr THEN BEGIN
  958.                                 PurgeSpace(total, contig);
  959.                                 IF (te^^.selEnd - te^^.selStart) + kTESlop > contig THEN
  960.                                     AlertUser(eNoSpaceCut,0)
  961.                                 ELSE BEGIN
  962.                                     TECut(te);
  963.                                 END; { if }
  964.                             END; { if }
  965.                         END; { iCut }
  966.  
  967.                         iCopy: 
  968.                             BEGIN
  969.                             IF ZeroScrap = noErr THEN BEGIN
  970.                                 TECopy(te);
  971.                             END; { if }
  972.                         END; { iCopy }
  973.  
  974.                         iPaste: 
  975.                             BEGIN
  976.                             IF TEGetScrapLen + (te^^.teLength - (te^^.selEnd - te^^.selStart)) > kMaxTELength THEN
  977.                                 AlertUser(eExceedPaste,0)
  978.                             ELSE BEGIN
  979.                                 aHandle := Handle(TEGetText(te));
  980.                                 oldSize := GetHandleSize(aHandle);
  981.                                 newSize := oldSize + TEGetScrapLen + kTESlop;
  982.                                 SetHandleSize(aHandle, newSize);
  983.                                 saveErr := MemError;
  984.                                 SetHandleSize(aHandle, oldSize);
  985.                                 IF saveErr <> noErr THEN
  986.                                     AlertUser(eNoSpacePaste,0)
  987.                                 ELSE
  988.                                     TEStylPaste(te);
  989.                             END; { if }
  990.                         END; { iPaste }
  991.  
  992.                         iClear: 
  993.                             TEDelete(te);
  994.  
  995.                         iSelectAll: 
  996.                             TESetSelect(0, te^^.teLength, te);
  997.  
  998.                     END; { case }
  999.                     IF menuItem <> iCopy THEN
  1000.                         AdjustScrollBars(window, FALSE);
  1001.                 END; { if }
  1002.             END; { mEdit }
  1003.  
  1004.             mFont: 
  1005.                 BEGIN { mFont }
  1006.                 GetItem(GetMHandle(mFont), menuItem, gFontName);
  1007.                 getFNum(gFontName, gFontID);
  1008.                 gTxStyle.tsFont := gFontID;
  1009.                 TESetStyle(doFont, gTxStyle, true, te);
  1010.                 AdjustScrollBars(window, FALSE);
  1011.             END; { mFont }
  1012.  
  1013.             mFontSize: 
  1014.                 BEGIN { mFontSize }
  1015.                 CASE menuItem OF
  1016.                     iNine: 
  1017.                         gFontSize := 9;
  1018.                     iTen: 
  1019.                         gFontSize := 10;
  1020.                     iTwelve: 
  1021.                         gFontSize := 12;
  1022.                     iFourteen: 
  1023.                         gFontSize := 14;
  1024.                     iEighteen: 
  1025.                         gFontSize := 18;
  1026.                     iTwoFour: 
  1027.                         gFontSize := 24;
  1028.                     iOther: 
  1029.                         gFontSize := GetNewFontSize;
  1030.                 END; { case }
  1031.                 gTxStyle.tsSize := gFontSize;
  1032.                 TESetStyle(doSize, gTxStyle, TRUE, te);
  1033.                 AdjustScrollBars(window, FALSE);
  1034.             END; { mFontSize }
  1035.  
  1036.             mStyle: 
  1037.                 BEGIN { mStyle }
  1038.                 WITH gTxStyle DO BEGIN
  1039.                     CASE menuItem OF
  1040.                         iPlain: 
  1041.                             BEGIN
  1042.                             anIntPtr := @gTxStyle.tsFace; { as per Tech Note #131 }
  1043.                             anIntPtr^ := 0;
  1044.                             tsFace := [];
  1045.                         END;
  1046.                         iBold: 
  1047.                             tsFace := [bold];
  1048.                         iItalic: 
  1049.                             tsFace := [italic];
  1050.                         iUnderline: 
  1051.                             tsFace := [underline];
  1052.                         iOutline: 
  1053.                             tsFace := [outline];
  1054.                         iShadow: 
  1055.                             tsFace := [shadow];
  1056.                     END; { case }
  1057.  
  1058.                     IF menuItem <> 1 THEN
  1059.                         TESetStyle(doFace + doToggle, gTxStyle, TRUE, te)
  1060.                          { if we don't select plain then use doToggle }
  1061.                     ELSE
  1062.                         TESetStyle(doFace, gTxStyle, TRUE, te);
  1063.                         { TESetStyle has problems with plain and doToggle-has no effect!}
  1064. {                          so we need to special case it. }
  1065.                     AdjustScrollBars(window, FALSE);
  1066.                 END; { with }
  1067.             END; { mStyle }
  1068.  
  1069.         END; { case }
  1070.         HiliteMenu(0); { unhighlight what MenuSelect (or MenuKey) hilited }
  1071.     END; { DoMenuCommand }
  1072.  
  1073. {$S Main}
  1074.     PROCEDURE DrawWindow (window: WindowPtr);
  1075.  
  1076. {    Draw the contents of an application window. }
  1077.  
  1078.     BEGIN { DrawWindow }
  1079.         SetPort(window);
  1080.         WITH window^ DO BEGIN
  1081.             EraseRect(portRect); { as per TextEdit chapter of Inside Macintosh }
  1082.             DrawControls(window); { this ordering makes for a better appearance }
  1083.             DrawGrowIcon(window);
  1084.             TEUpdate(portRect, DocumentPeek(window)^.docTE);
  1085.         END; { with }
  1086.     END; { DrawWindow }
  1087.  
  1088. {$S Main}
  1089.     FUNCTION GetSleep: LONGINT;
  1090.  
  1091. {    Calculate a sleep value for WaitNextEvent. This takes into account the things}
  1092. {     that DoIdle does with idle time. }
  1093.  
  1094.         VAR
  1095.             sleep: LONGINT;
  1096.             window: WindowPtr;
  1097.  
  1098.     BEGIN { GetSleep }
  1099.         sleep := MAXLONGINT; { default value for sleep }
  1100.         IF NOT gInBackground THEN BEGIN { if we are in front... }
  1101.             window := FrontWindow; { and the front window is ours... }
  1102.             IF IsAppWindow(window) THEN BEGIN
  1103.                 WITH DocumentPeek(window)^.docTE^^ DO
  1104.                     IF selStart = selEnd THEN { and the selection is an insertion point... }
  1105.                         sleep := GetCaretTime; { we need to blink the insertion point }
  1106.             END; { if }
  1107.         END; { if }
  1108.         GetSleep := sleep;
  1109.     END; { GetSleep }
  1110.  
  1111. {$S Main}
  1112.     PROCEDURE CommonAction (control: ControlHandle; VAR amount: INTEGER);
  1113.  
  1114. {    Common algorithm for setting the new value of a control. It returns the actual amount}
  1115. {    the value of the control changed. Note the pinning is done for the sake of returning}
  1116. {    the amount the control value changed. }
  1117.  
  1118.         VAR
  1119.             value, max: INTEGER;
  1120.             window: WindowPtr;
  1121.  
  1122.     BEGIN { CommonAction }
  1123.         value := GetCtlValue(control); { get current value }
  1124.         max := GetCtlMax(control); { and max value }
  1125.         amount := value - amount;
  1126.         IF amount < 0 THEN
  1127.             amount := 0
  1128.         ELSE IF amount > max THEN
  1129.             amount := max;
  1130.         SetCtlValue(control, amount);
  1131.         amount := value - amount; { calculate true change }
  1132.     END; { CommonAction }
  1133.  
  1134. {$S Main}
  1135.     PROCEDURE VActionProc (control: ControlHandle; part: INTEGER);
  1136.  
  1137. {    Determines how much to change the value of the vertical scrollbar by and how}
  1138. {    much to scroll the TE record. }
  1139.  
  1140.         VAR
  1141.             amount: INTEGER;
  1142.             window: WindowPtr;
  1143.  
  1144.     BEGIN { VActionProc }
  1145.         IF part <> 0 THEN BEGIN
  1146.             window := control^^.contrlOwner;
  1147.             WITH DocumentPeek(window)^, DocumentPeek(window)^.docTE^^ DO BEGIN
  1148.                 CASE part OF
  1149.                     inUpButton, inDownButton: 
  1150.                         amount := 24;
  1151.                     inPageUp, inPageDown: 
  1152.                         amount := viewRect.bottom - viewRect.top; { one page }
  1153.                 END; { case }
  1154.                 IF (part = inDownButton) | (part = inPageDown) THEN
  1155.                     amount := -amount; { reverse direction }
  1156.                 CommonAction(control, amount);
  1157.                 IF amount <> 0 THEN
  1158.                     TEScroll(0, amount, docTE);
  1159.             END; { with }
  1160.         END; { if }
  1161.     END; { VActionProc }
  1162.  
  1163. {$S Main}
  1164.     PROCEDURE HActionProc (control: ControlHandle; part: INTEGER);
  1165.  
  1166. {    Determines how much to change the value of the horizontal scrollbar by and how}
  1167. {    much to scroll the TE record. }
  1168.  
  1169.         VAR
  1170.             amount: INTEGER;
  1171.             window: WindowPtr;
  1172.  
  1173.     BEGIN { HActionProc }
  1174.         IF part <> 0 THEN BEGIN
  1175.             window := control^^.contrlOwner;
  1176.             WITH DocumentPeek(window)^, DocumentPeek(window)^.docTE^^ DO BEGIN
  1177.                 CASE part OF
  1178.                     inUpButton, inDownButton: 
  1179.                         amount := kButtonScroll; { a few pixels }
  1180.                     inPageUp, inPageDown: 
  1181.                         amount := viewRect.right - viewRect.left; { a page }
  1182.                 END; { case }
  1183.                 IF (part = inDownButton) | (part = inPageDown) THEN
  1184.                     amount := -amount; { reverse direction }
  1185.                 CommonAction(control, amount);
  1186.                 IF amount <> 0 THEN
  1187.                     TEScroll(amount, 0, docTE);
  1188.             END; { with }
  1189.         END; { if }
  1190.     END; { HActionProc }
  1191.  
  1192. {$S Main}
  1193.     PROCEDURE DoIdle;
  1194.  
  1195. {    This is called whenever we get an null event or a mouse-moved event.}
  1196. {     It takes care of necessary periodic actions. For this program, it calls TEIdle. }
  1197.  
  1198.         VAR
  1199.             window: WindowPtr;
  1200.  
  1201.     BEGIN { DoIdle }
  1202.         window := FrontWindow;
  1203.         IF IsAppWindow(window) THEN
  1204.             TEIdle(DocumentPeek(window)^.docTE);
  1205.     END; { DoIdle }
  1206.  
  1207. {$S Main}
  1208.     PROCEDURE DoKeyDown (event: EventRecord);
  1209.  
  1210. {    This is called for any keyDown or autoKey events, except when the}
  1211. {    Command key is held down. It looks at the frontmost window to decide what}
  1212. {     to do with the key typed. }
  1213.  
  1214.         VAR
  1215.             window: WindowPtr;
  1216.             key: CHAR;
  1217.             te: TEHandle;
  1218.  
  1219.     BEGIN
  1220.         window := FrontWindow;
  1221.         IF IsAppWindow(window) THEN BEGIN
  1222.             te := DocumentPeek(window)^.docTE;
  1223.             key := CHR(BAnd(event.message, charCodeMask));
  1224.             IF (key = CHR(kDelChar)) | (te^^.teLength - (te^^.selEnd - te^^.selStart) + 1 < kMaxTELength) THEN     { don't count deletes }
  1225.                 BEGIN    { but check haven't gone past }
  1226.                 TEKey(key, te);
  1227.                 AdjustScrollbars(window, FALSE);
  1228.             END
  1229.             ELSE
  1230.                 AlertUser(eExceedChar,0);
  1231.         END; { if }
  1232.     END; { DoKeyDown }
  1233.  
  1234. {$S Main}
  1235.     PROCEDURE DoContentClick (window: WindowPtr; event: EventRecord);
  1236.  
  1237. {    Called when a mouseDown occurs in the content of a window. }
  1238.  
  1239.         VAR
  1240.             mouse: Point;
  1241.             control: ControlHandle;
  1242.             part, value: INTEGER;
  1243.             shiftDown: BOOLEAN;
  1244.             teRect: Rect;
  1245.  
  1246.     BEGIN { DoContentClick }
  1247.         IF IsAppWindow(window) THEN BEGIN
  1248.             SetPort(window);
  1249.             mouse := event.where; { get the click position }
  1250.             GlobalToLocal(mouse); { convert to local coordinates }
  1251.  
  1252.             GetTERect(window, teRect);
  1253.             IF PtInRect(mouse, teRect) THEN BEGIN
  1254.                 shiftDown := BAnd(event.modifiers, shiftKey) <> 0; { extend if Shift is down }
  1255.                 TEClick(mouse, shiftDown, DocumentPeek(window)^.docTE);
  1256.             END
  1257.             ELSE BEGIN
  1258.                 part := FindControl(mouse, window, control);
  1259.                 WITH DocumentPeek(window)^ DO
  1260.                     CASE part OF
  1261.                         0: 
  1262.                             ;     { do nothing for viewRect case }
  1263.                         inThumb: 
  1264.                             BEGIN
  1265.                             value := GetCtlValue(control);
  1266.                             part := TrackControl(control, mouse, NIL);
  1267.                             IF part <> 0 THEN BEGIN
  1268.                                 value := value - GetCtlValue(control);
  1269.                                 IF value <> 0 THEN
  1270.                                     IF control = docVScroll THEN
  1271.                                         TEScroll(0, value, docTE)
  1272.                                     ELSE
  1273.                                         TEScroll(value, 0, docTE);
  1274.                             END; { if }
  1275.                         END; { inThumb }
  1276.                         OTHERWISE    { must be page or button }
  1277.                             IF control = docVScroll THEN
  1278.                                 value := TrackControl(control, mouse, @VActionProc)
  1279.                             ELSE
  1280.                                 value := TrackControl(control, mouse, @HActionProc);
  1281.                     END; { case }
  1282.             END; { if }
  1283.         END; { if }
  1284.     END; { DoContentClick }
  1285.  
  1286. {$S Main}
  1287.     PROCEDURE ResizeWindow (window: WindowPtr);
  1288.  
  1289. {    Called when the window has been resized to fix up the controls and content }
  1290.  
  1291.     BEGIN { ResizeWindow }
  1292.         WITH window^ DO BEGIN
  1293.             AdjustScrollbars(window, TRUE);
  1294.             AdjustTE(window);
  1295.             InvalRect(portRect);
  1296.         END;
  1297.     END; { ResizeWindow }
  1298.  
  1299. {$S Main}
  1300.     PROCEDURE GetLocalUpdateRgn (window: WindowPtr; localRgn: RgnHandle);
  1301.  
  1302. {    Returns the update region in local coordinates }
  1303.  
  1304.     BEGIN { GetLocalUpdateRgn }
  1305.         CopyRgn(WindowPeek(window)^.updateRgn, localRgn); { save old update region }
  1306.         WITH window^.portBits.bounds DO
  1307.             OffsetRgn(localRgn, left, top); { convert to local coords }
  1308.     END; { GetLocalUpdateRgn }
  1309.  
  1310. {$S Main}
  1311.     PROCEDURE DoGrowWindow (window: WindowPtr; event: EventRecord);
  1312.  
  1313. {    Called when a mouseDown occurs in the grow box of an active window. In}
  1314. {     order to eliminate any 'flicker', we want to invalidate only what is}
  1315. {     necessary. Since ResizeWindow invalidates the whole portRect, we save}
  1316. {     the old TE viewRect, intersect it with the new TE viewRect, and}
  1317. {     remove the result from the update region. However, we must make sure}
  1318. {     that any old update region that might have been around gets put back. }
  1319.  
  1320.         VAR
  1321.             growResult: LONGINT;
  1322.             tempRect: Rect;
  1323.             tempRgn: RgnHandle;
  1324.             ignoreResult: BOOLEAN;
  1325.  
  1326.     BEGIN { DoGrowWindow }
  1327.         WITH screenBits.bounds DO
  1328.             SetRect(tempRect, kMinDocDim, kMinDocDim, right, bottom); { set up limiting values }
  1329.         growResult := GrowWindow(window, event.where, tempRect);
  1330.         IF growResult <> 0 THEN  { see if changed size }
  1331.             WITH DocumentPeek(window)^, window^ DO BEGIN
  1332.                 tempRect := docTE^^.viewRect; { save old text box }
  1333.                 tempRgn := NewRgn;
  1334.                 GetLocalUpdateRgn(window, tempRgn); { get localized update region }
  1335.                 SizeWindow(window, LoWrd(growResult), HiWrd(growResult), TRUE);
  1336.                 ResizeWindow(window);
  1337.                 ignoreResult := SectRect(tempRect, docTE^^.viewRect, tempRect); { find what stayed same }
  1338.                 ValidRect(tempRect); { take it out of update }
  1339.                 InvalRgn(tempRgn); { put back any prior update }
  1340.                 DisposeRgn(tempRgn);
  1341.             END; { with }
  1342.     END; { DoGrowWindow }
  1343.  
  1344. {$S Main}
  1345.     PROCEDURE DoZoomWindow (window: WindowPtr; part: INTEGER);
  1346.  
  1347. {    Called when a mouseClick occurs in the zoom box of an active window.}
  1348. {    Everything has to get re-drawn here, so we don't mind that}
  1349. {    ResizeWindow invalidates the whole portRect. }
  1350.  
  1351.     BEGIN { DoZoomWindow }
  1352.         WITH window^ DO BEGIN
  1353.             EraseRect(portRect);
  1354.             ZoomWindow(window, part, (window = FrontWindow));
  1355.             ResizeWindow(window);
  1356.         END; { with }
  1357.     END; { DoZoomWindow }
  1358.  
  1359. {$S Main}
  1360.     PROCEDURE DoUpdate (window: WindowPtr);
  1361.  
  1362. {    This is called when an update event is received for a window.}
  1363. {     It calls DrawWindow to draw the contents of an application window,}
  1364. {     but only if the visRgn is non-empty; for efficiency reasons,}
  1365. {     not because it is required. }
  1366.  
  1367.     BEGIN { DoUpdate }
  1368.         IF IsAppWindow(window) THEN BEGIN
  1369.             BeginUpdate(window); { this sets up the visRgn }
  1370.             IF NOT EmptyRgn(window^.visRgn) THEN    { draw if updating needs to be done }
  1371.                 DrawWindow(window);
  1372.             EndUpdate(window);
  1373.         END; { if }
  1374.     END; { DoUpdate }
  1375.  
  1376. {$S Main}
  1377.     PROCEDURE DoActivate (window: WindowPtr; becomingActive: BOOLEAN);
  1378.  
  1379. {    This is called when a window is activated or deactivated. }
  1380.  
  1381.         VAR
  1382.             tempRgn, clipRgn: RgnHandle;
  1383.             growRect: Rect;
  1384.  
  1385.     BEGIN { DoActivate }
  1386.         IF IsAppWindow(window) THEN
  1387.             WITH DocumentPeek(window)^ DO
  1388.                 IF becomingActive THEN BEGIN
  1389.                 { since we don’t want TEActivate to draw a selection in an area where}
  1390. {                  we’re going to erase and redraw, we’ll clip out the update region}
  1391. {                  before calling it. }
  1392.                     tempRgn := NewRgn;
  1393.                     clipRgn := NewRgn;
  1394.                     GetLocalUpdateRgn(window, tempRgn); { get localized update region }
  1395.                     GetClip(clipRgn);
  1396.                     DiffRgn(clipRgn, tempRgn, tempRgn); { subtract updateRgn from clipRgn }
  1397.                     SetClip(tempRgn);
  1398.                     TEActivate(docTE); { let TE do its thing }
  1399.                     SetClip(clipRgn); { restore the full-blown clipRgn }
  1400.                     DisposeRgn(tempRgn);
  1401.                     DisposeRgn(clipRgn);
  1402.  
  1403.                 {the controls need to be redrawn on activation:}
  1404.                     docVScroll^^.contrlVis := kControlVisible;
  1405.                     docHScroll^^.contrlVis := kControlVisible;
  1406.                     InvalRect(docVScroll^^.contrlRect);
  1407.                     InvalRect(docHScroll^^.contrlRect);
  1408.                 { the growbox needs to be redrawn on activation: }
  1409.                     growRect := window^.portRect;
  1410.                     WITH growRect DO BEGIN
  1411.                         top := bottom - kScrollbarAdjust; { adjust for the scrollbars }
  1412.                         left := right - kScrollbarAdjust;
  1413.                     END; { with }
  1414.                     InvalRect(growRect);
  1415.                 END
  1416.                 ELSE BEGIN
  1417.                     TEDeactivate(docTE);
  1418.                 { the controls should be hidden immediately on deactivation: }
  1419.                     HideControl(docVScroll);
  1420.                     HideControl(docHScroll);
  1421.                 { the growbox should be changed immediately on deactivation: }
  1422.                     DrawGrowIcon(window);
  1423.                 END; { if }
  1424.     END; { DoActivate }
  1425.  
  1426. {$S Main}
  1427.     PROCEDURE GetGlobalMouse (VAR mouse: Point);
  1428.  
  1429. {Get the global coordinates of the mouse. When you call OSEventAvail}
  1430. { it will return either a pending event or a null event. In either case,}
  1431. { the where field of the event record will contain the current position}
  1432. { of the mouse in global coordinates and the modifiers field will reflect}
  1433. { the current state of the modifiers. Another way to get the global}
  1434. { coordinates is to call GetMouse and LocalToGlobal, but that requires}
  1435. { being sure that thePort is set to a valid port.}
  1436.  
  1437.         VAR
  1438.             event: EventRecord;
  1439.  
  1440.     BEGIN
  1441.         IF OSEventAvail(kNoEvents, event) THEN
  1442.             ;    {we aren't interested in any events}
  1443.         mouse := event.where;                    {just the mouse position}
  1444.     END;
  1445.  
  1446. {$S Main}
  1447.     PROCEDURE AdjustCursor (mouse: Point; region: RgnHandle);
  1448.  
  1449. { Change the cursor's shape, depending on its position. This also calculates a region}
  1450. { that includes the cursor for WaitNextEvent. }
  1451.  
  1452.         VAR
  1453.             window: WindowPtr;
  1454.             arrowRgn: RgnHandle;
  1455.             iBeamRgn: RgnHandle;
  1456.             iBeamRect: Rect;
  1457.  
  1458.     BEGIN { AdjustCursor }
  1459.         window := FrontWindow; { we only adjust the cursor when we are in front }
  1460.         IF (NOT gInBackground) AND (NOT IsDAWindow(window)) THEN BEGIN
  1461.         { calculate regions for different cursor shapes}
  1462.             arrowRgn := NewRgn;
  1463.             iBeamRgn := NewRgn;
  1464.  
  1465.         { start with a big, big rectangular region }
  1466.             SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
  1467.  
  1468.         { calculate iBeamRgn }
  1469.             IF IsAppWindow(window) THEN BEGIN
  1470.                 iBeamRect := DocumentPeek(window)^.docTE^^.viewRect;
  1471.                 SetPort(window); { make a global version of the viewRect }
  1472.                 WITH iBeamRect DO BEGIN
  1473.                     LocalToGlobal(topLeft);
  1474.                     LocalToGlobal(botRight);
  1475.                 END; { with }
  1476.                 RectRgn(iBeamRgn, iBeamRect);
  1477.                 WITH window^.portBits.bounds DO
  1478.                     SetOrigin(-left, -top);
  1479.                 SectRgn(iBeamRgn, window^.visRgn, iBeamRgn);
  1480.                 SetOrigin(0, 0);
  1481.             END; { if }
  1482.  
  1483.         { subtract other regions from arrowRgn }
  1484.             DiffRgn(arrowRgn, iBeamRgn, arrowRgn);
  1485.  
  1486.         {change the cursor and the region parameter}
  1487.             IF PtInRgn(mouse, iBeamRgn) THEN BEGIN
  1488.                 SetCursor(GetCursor(iBeamCursor)^^);
  1489.                 CopyRgn(iBeamRgn, region);
  1490.             END
  1491.             ELSE BEGIN
  1492.                 SetCursor(arrow);
  1493.                 CopyRgn(arrowRgn, region);
  1494.             END; { if }
  1495.  
  1496.         { get rid of our local regions }
  1497.             DisposeRgn(arrowRgn);
  1498.             DisposeRgn(iBeamRgn);
  1499.         END; { if }
  1500.     END; { AdjustCursor }
  1501.  
  1502. {$S Main}
  1503.     PROCEDURE DoEvent (event: EventRecord);
  1504.  
  1505. {    Do the right thing for an event. Determine what kind of event it is, and call}
  1506. {     the appropriate routines. }
  1507.  
  1508.         VAR
  1509.             part, err: INTEGER;
  1510.             window: WindowPtr;
  1511.             key: CHAR;
  1512.             ignore: BOOLEAN;
  1513.             aPoint: Point;
  1514.  
  1515.     BEGIN { DoEvent }
  1516.         CASE event.what OF
  1517.             nullEvent: 
  1518.                 DoIdle;
  1519.             mouseDown: 
  1520.                 BEGIN
  1521.                 part := FindWindow(event.where, window);
  1522.                 CASE part OF
  1523.  
  1524.                     inMenuBar: 
  1525.                         BEGIN
  1526.                         AdjustMenus;
  1527.                         DoMenuCommand(MenuSelect(event.where));
  1528.                     END; { inMenuBar }
  1529.  
  1530.                     inSysWindow: 
  1531.                         SystemClick(event, window);
  1532.  
  1533.                     inContent: 
  1534.                         IF window <> FrontWindow THEN BEGIN
  1535.                             SelectWindow(window);
  1536.                         {DoEvent(event);}
  1537.     {use this line for "do first click"}
  1538.                         END
  1539.                         ELSE
  1540.                             DoContentClick(window, event);
  1541.  
  1542.                     inDrag: 
  1543.                         DragWindow(window, event.where, screenBits.bounds);
  1544.  
  1545.                     inGrow: 
  1546.                         DoGrowWindow(window, event);
  1547.  
  1548.                     inGoAway: 
  1549.                         IF TrackGoAway(window, event.where) THEN
  1550.                             ignore := DoCloseWindow(window); { we don't care if cancelled }
  1551.  
  1552.                     inZoomIn, inZoomOut: 
  1553.  
  1554.                         IF TrackBox(window, event.where, part) THEN
  1555.                             DoZoomWindow(window, part);
  1556.                 END; { case }
  1557.             END; { mouseDown }
  1558.  
  1559.             keyDown, autoKey: 
  1560.                 BEGIN
  1561.                 key := CHR(BAnd(event.message, charCodeMask));
  1562.                 IF BAnd(event.modifiers, cmdKey) <> 0 THEN BEGIN { Command key down }
  1563.                     IF event.what = keyDown THEN BEGIN
  1564.                         AdjustMenus; { enable/disable/check menu items properly }
  1565.                         DoMenuCommand(MenuKey(key));
  1566.                     END; { if }
  1567.                 END
  1568.                 ELSE
  1569.                     DoKeyDown(event);
  1570.             END; { keyDown }
  1571.  { call DoActivate with the window and... }
  1572.  
  1573.             activateEvt: { TRUE for activate, FALSE for deactivate }
  1574.                 DoActivate(WindowPtr(event.message), BAND(event.modifiers, activeFlag) <> 0);
  1575.  
  1576.             updateEvt: { call DoUpdate with the window to update }
  1577.                 DoUpdate(WindowPtr(event.message));
  1578.  
  1579.             diskEvt: 
  1580.                 IF HiWrd(event.message) <> noErr THEN BEGIN
  1581.                     SetPt(aPoint, kDILeft, kDITop);
  1582.                     err := DIBadMount(aPoint, event.message);
  1583.                 END;
  1584.  
  1585.             kOSEvent: 
  1586.                 CASE BAnd(BRotL(event.message, 8), $FF) OF    { high byte of message }
  1587.                     kMouseMovedMessage: 
  1588.                         DoIdle; { mouse moved is also an idle event }
  1589.  
  1590.                     kSuspendResumeMessage: 
  1591.                         BEGIN
  1592.                         gInBackground := BAnd(event.message, kResumeMask) = 0;
  1593.                         DoActivate(FrontWindow, NOT gInBackground);
  1594.                     END; { kSuspendResumeMessage }
  1595.                 END;
  1596.         END; { case }
  1597.     END; { DoEvent }
  1598.  
  1599. {$S Main}
  1600.     PROCEDURE EventLoop;
  1601.  
  1602. {    Get events forever, and handle them by calling DoEvent.}
  1603. {     Also call AdjustCursor each time through the loop. }
  1604.  
  1605.         VAR
  1606.             cursorRgn: RgnHandle;
  1607.             gotEvent: BOOLEAN;
  1608.             event: EventRecord;
  1609.             mouse: Point;
  1610.  
  1611.     BEGIN { EventLoop }
  1612.         cursorRgn := NewRgn; { we'll pass an empty region to WNE the first time thru }
  1613.         REPEAT
  1614.             IF gHasWaitNextEvent THEN BEGIN
  1615.                 GetGlobalMouse(mouse);        {since we might go to sleep}
  1616.                 AdjustCursor(mouse, cursorRgn);
  1617.                 gotEvent := WaitNextEvent(everyEvent, event, GetSleep, cursorRgn)
  1618.             END
  1619.             ELSE BEGIN
  1620.                 SystemTask;
  1621.                 gotEvent := GetNextEvent(everyEvent, event);
  1622.             END; { if }
  1623.             IF gotEvent THEN BEGIN
  1624.                 AdjustCursor(event.where, cursorRgn);
  1625.                 DoEvent(event);
  1626.             END
  1627.             ELSE
  1628.                 DoIdle;
  1629.         UNTIL FALSE; { loop forever }
  1630.     END; { EventLoop }
  1631.  
  1632.     PROCEDURE _DataInit;
  1633.     EXTERNAL;
  1634.  
  1635. {    This routine is automatically linked in by the MPW Linker. This external}
  1636. {    reference to it is done so that we can unload its segment, %A5Init. }
  1637.  
  1638. {$S Main}
  1639. BEGIN { main program }
  1640.     UnloadSeg(@_DataInit);    { note that _DataInit must not be in Main! }
  1641.     MaxApplZone;                { expand the heap so code segments load at the top }
  1642.     Initialize;                    { initialize the program }
  1643.     UnloadSeg(@Initialize);    { note that Initialize must not be in Main! }
  1644.     EventLoop;                    { call the main event loop }
  1645. END. { main program }